// vue2响应式原理：在内部通过Object.defineProperty API劫持数据的变化，在数据访问时依赖收集，在数据修改时通知依赖更新

// vue2 缺点：1.初始化阶段递归 2.不能检测对象属性的新增和删除 3.数组改变length是无效的

// 数组方法劫持
let oldArrayPrototype = Array.prototype
let proto = Object.create(oldArrayPrototype)
;['push','pop','shift','unshift','splice','sort','reverse'].forEach(method=>{
    proto[method] = function(){ // 函数劫持，把函数重写，内部继续调用老的方法
        updateView()
        oldArrayPrototype[method].call(this,...arguments)
    }
})


function observe(target){
    console.log(11)
    if(typeof target !== 'object' || target === null){
        return target
    }
    if(Array.isArray(target)){
        target.__proto__ = proto // Object.setPrototypeOf(target,proto)

    }
    for (const key in target) {
        defineReactive(target,key,target[key])
    }
}

function defineReactive(target, key, value) {
    // observe(value) // 递归检测
    Object.defineProperty(target,key,{
        get(){
            observe(value) // 递归检测   自我感觉在get中递归更好。不应该写在Object.defineProperty上面
            return value
        },
        set(newVal){
            if(newVal!==value){
                observe(newVal) // 递归检测
                updateView()
                value = newVal
            }

        }
    })
}

function updateView() {
    console.log("视图更新")
}

let data = {
    name:'zxw',
    study:{
        sports:"running",
        course:"vue"
    },
    likes:['food','sports','flower']
}
observe(data)

// data.name = 'jjk'
// console.log(data.name)
//
data.study.sports='swim'
console.log(data.study.sports)

// data.study = {
//     sports:"running",
//     like:'food',
//     aaaa:'1111',
//
// }
// data.study.sports='swim' // 此时视图不会更新，因为这是新的属性值
// console.log(data.study.sports)

// data.study.like = 'aaaa' // ????????
// console.log(data.study.like)

// data.study.aaa = 'swim' // 此时视图不会更新，因为这是新的属性值
// console.log(data.study.aaa)

// 数组的检测需要对数组上的方法重写
// 但是不能直接Array.prototype.push = ...., 这样就把没被观察的数据也被重写了
// 再创建一个，不覆盖原型上的方法
// data.likes.push("swim")